<?php
/**
 * 获取和设置配置参数 支持批量定义
 * 如果$key是关联型数组，则会按K-V的形式写入配置
 * 如果$key是数字索引数组，则返回对应的配置数组
 * @param string|array $name 配置变量
 * @param mixed $value 配置值
 * @return mixed
 */
function C($key,$value=null){
    static $_config = array();
    $args = func_num_args();
    if($args == 1){
        if(is_string($key)){  //如果传入的key是字符串
            return isset($_config[$key])?$_config[$key]:null;
        }
        if(is_array($key)){
            if(array_keys($key) !== range(0, count($key) - 1)){  //如果传入的key是关联数组
                $_config = array_merge($_config, $key);
            }else{
                $ret = array();
                foreach ($key as $k) {
                    $ret[$k] = isset($_config[$k])?$_config[$k]:null;
                }
                return $ret;
            }
        }
    }else{
        $_config[$key] = $value;
    }
    return null;
}
function halt($str){
    header("Content-Type:text/html; charset=utf-8");
    echo "<pre>";
    debug_print_backtrace();
    echo "</pre>";
    die($str);
}
/**
 * 用于实例化一个没有模型文件的Model
 * @param string $name 数据库表名称
 * @return Model
 */
function M(){
    return DB::getInstance();
}
function includeIfExist($path){
    if(file_exists($path)){
        include $path;
    }
}
class SinglePHP {
    private $m;
    private $a;
    private static $_instance;
    private function __construct($conf){
        C($conf);
    }
    private function __clone(){}
    public static function getInstance($conf){
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self($conf);
        }
        return self::$_instance;
    }
    /**
     * 运行应用实例
     * @access public
     * @return void
     */
    public function run(){
        C('APP_FULL_PATH', getcwd().'/'.C('APP_PATH').'/');
        $path_mod = C('PATH_MOD');
        if(strcmp(strtoupper($path_mod),'NORMAL') === 0 || !isset($_SERVER['PATH_INFO'])){
            $this->m = isset($_GET['m'])?$_GET['m']:'Index';
            $this->a = isset($_GET['a'])?$_GET['a']:'Index';
        }else{
            $path_info = isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'';
            $path_info_arr = explode('/',trim($path_info,'/'));
            if(isset($path_info_arr[0]) && $path_info_arr[0] !== ''){
                $this->m = $path_info_arr[0];
            }else{
                $this->m = 'Index';
            }
            if(isset($path_info_arr[1])){
                $this->a = $path_info_arr[1];
            }else{
                $this->a = 'Index';
            }
        }
        includeIfExist(getcwd().'/'.C('APP_PATH').'/Controller/'.$this->m.'Controller.class.php');
        if(!class_exists($this->m.'Controller')){
            includeIfExist(getcwd().'/'.C('APP_PATH').'/Controller/EmptyController.class.php');
            if(!class_exists('EmptyController')){
                halt('模块'.$this->m.'不存在');
            }
        }
        $moduleClass = $this->m.'Controller';
        $module = new $moduleClass();
        if(!method_exists($module, $this->a.'Action')){
            if(!method_exists($module, 'EmptyAction')){
                halt('方法'.$this->a.'不存在');
            }else{
                $this->a = 'Empty';
            }
        }
        includeIfExist( getcwd().'/'.C('APP_PATH').'/common.php');
        call_user_func(array($module,$this->a.'Action'));
    }
}
class Controller {
    private $_view;
    public function __construct(){
        $this->_view = new View();
        $this->_init();
    }
    protected function _init(){}
    protected function display($tpl=''){
        if($tpl === ''){
            $trace = debug_backtrace();
            $module = substr($trace[1]['class'], 0, -10);
            $action = substr($trace[1]['function'], 0 , -6);
            $tpl = $module . '/' . $action;
        }elseif(strpos($tpl, '/') === false){
            $trace = debug_backtrace();
            $module = substr($trace[1]['class'], 0, -10);
            $tpl = $module . '/' . $tpl;
        }
        $this->_view->display($tpl);
    }
    protected function assign($key,$value){
        $this->_view->assign($key,$value);
    }
}
class View {
    private $_tpl_dir;
    private $_view_path;
    private static $_include_tpl;
    private $_data = array();
    public function __construct(){
        $this->tpl_dir = './'.C('APP_PATH').'/View/';
    }
    public function assign($key, $value) {
        $this->_data[$key] = $value;
    }
    public function display($tpl_file) {
        $this->_view_path = $this->tpl_dir . $tpl_file . '.php';
        unset($tpl_file);
        extract($this->_data);
        include $this->_view_path;
    }
    public static function tplInclude($path){
        self::$_include_tpl = C('APP_FULL_PATH') . '/View/' . $path . '.php';
        unset($path);
        include self::$_include_tpl;
    }
}

class DB {
    private $_db;
    private $_lastSql;
    private $_rows;
    private $_error;
    private static $_instance;
    private function __construct(){
        $db_conf = C(array('DB_HOST','DB_PORT','DB_USER','DB_PWD','DB_NAME','DB_CHARSET'));
        if(!isset($db_conf['DB_PORT'])){
            $db_conf['DB_PORT'] = '3306';
        }
        if(!isset($db_conf['DB_CHARSET'])){
            $db_conf['DB_CHARSET'] = 'utf8';
        }
        $this->_db = mysql_connect($db_conf['DB_HOST'].':'.$db_conf['DB_PORT'],$db_conf['DB_USER'],$db_conf['DB_PWD']);
        if($this->_db === false){
            halt(mysql_error());
        }
        $select_db = mysql_select_db($db_conf['DB_NAME'],$this->_db);
        if($select_db === false){
            halt(mysql_error());
        }
        mysql_query("set names {$db_conf['DB_CHARSET']}");
    }
    private function __clone(){}
    static public function getInstance(){
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    public function escape($str){
        return mysql_real_escape_string($str, $this->_db);
    }
    public function query($sql){
        $this->_lastSql = $sql;
        $this->logSql();
        $res = mysql_query($sql,$this->_db);
        if($res === false){
            $this->_error = mysql_error($this->_db);
            $this->logError();
            return false;
        }else{
            $this->_rows = mysql_num_rows($res);
            $result = array();
            if($this->_rows >0) {
                while($row = mysql_fetch_array($res, MYSQL_ASSOC)){
                    $result[]   =   $row;
                }
                mysql_data_seek($res,0);
            }
            return $result;
        }
    }
    public function execute($sql) {
        $this->_lastSql = $sql;
        $this->logSql();
        $result =   mysql_query($sql, $this->_db) ;
        if ( false === $result) {
            $this->_error = mysql_error($this->_db);
            $this->logError();
            return false;
        } else {
            $this->_rows = mysql_affected_rows($this->_db);
            return $this->_rows;
        }
    }
    public function insertId() {
        return mysql_insert_id($this->_db);
    }
    public function lastSql(){
        return $this->_lastSql;
    }
    public function error(){
        return $this->_error;
    }
    private function logSql(){
        /*require_once "BaeLog.class.php";
        $logger = BaeLog::getInstance();
        $logger ->logDebug($this->_lastSql);*/
    }
    private function logError(){
        /*require_once "BaeLog.class.php";
        $logger = BaeLog::getInstance();
        $str = $this->_lastSql . ' ' . $this->_error;
        $logger ->logFatal($str);*/
        //file_put_contents('./'.C('APP_PATH').'/sqlError.log', $str, FILE_APPEND);
    }
}